﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Sheeps
{
    public class StandardSheepBehavior : SheepBehaviorAlogorithm
    {

        public override void UpdatePositions(GameState gameState)
        {

            UpdateVirtualPositions(gameState);
            
            foreach (var sh in gameState.SheepList)
            {
                // Sheep will stay near their flock if scared by the dog                     
                if (sh.IsScared)
                {
                    Vector3 flockMiddle = FindFlockMiddle(sh, gameState.SheepList);
                    if (sh.VirtualPosition != flockMiddle)
                    {
                        flockMiddle.Normalize();
                        flockMiddle *= (2 * DefaultSettings.SHEEP_MAX_MOVE_LENGTH);
                        /*
                        Vector3 temp = (sh.VirtualPosition + flockMiddle) - sh.VirtualPosition;
                        temp.Normalize();
                        temp *= DefaultSettings.SHEEP_MAX_MOVE_LENGTH;
                        sh.Position += temp;
                        */
                        sh.Position += flockMiddle;
                    }
                    else
                    {
                        sh.Position = sh.VirtualPosition;
                    }
                    sh.IsScared = false;
                }
                else
                {
                    sh.Position = sh.VirtualPosition;
                    sh.IsScared = false;
                }
            }
         
            return;
        }

        /// <summary>
        /// This method finds the flock middle for one of the sheep
        /// </summary>
        /// <param name="sheep">Sheep that the flock middle needs to be found for</param>
        /// <param name="ls">List of all sheeps</param>
        /// <returns>Returns a vector, which represents the flock middle</returns>
        public Vector3 FindFlockMiddle(Sheep sheep, List<Sheep> ls)
        {
            Vector3 flockMiddle = new Vector3(0,0,0);
            foreach (var sh in ls)
            {
                double distance = (sheep.Position - sh.Position).Magnitude;
                if ((distance < DefaultSettings.SHEEP_FLOCK_SENSIBILITY) && sh.IsScared && !(OppositeVectors(sheep.VirtualPosition, sh.VirtualPosition)))
                {
                    flockMiddle += sh.VirtualPosition;
                }
            }
            return flockMiddle;
        }

        /// <summary>
        /// This method finds the directions in which the sheep would move
        /// if they were the only one escaping the dog
        /// </summary>
        /// <param name="gameState">Current game state</param>
        public void UpdateVirtualPositions(GameState gameState)
        {
            Random rand = new Random();
            foreach(var sh in gameState.SheepList)
            {                                        
                if (sh.IsScared)
                {
                    Vector3 VirtualPosition = sh.Position - gameState.Dog.Position;
                    int r = (int)Math.Pow(-1, rand.Next() % 2);
                    VirtualPosition.Normalize();
                    VirtualPosition = VirtualPosition * sh.MaxMoveLength;  

                    // Sheep will run away from a dog in a small random angle
                    Vector3 Perp = new Vector3(r * VirtualPosition.Y, r * r * VirtualPosition.X, 0);
                    Perp.Normalize();
                    Perp = Perp * 10;
                    VirtualPosition = VirtualPosition + Perp;
                    sh.VirtualPosition = sh.Position + VirtualPosition;
                }
                else
                {                    
                    // If sheep are not scared by the dog, 
                    // they will continue to eat grass and move randomly
                    int randX = rand.Next()%1000 - 500;
                    int randY = rand.Next()%1000 - 500;
                    Vector3 random = new Vector3(randX, randY, 0);
                    if(random.Magnitude != 0)
                        random.Normalize();
                    random *= DefaultSettings.SHEEP_MAX_RANDOM_MOVE;
                    sh.VirtualPosition = sh.Position + random;   
                }
            }

            return;
        }

        /// <summary>
        /// Decides if two vectors have opposite senses
        /// </summary>
        /// <param name="v1">first vector</param>
        /// <param name="v2">second vector</param>
        /// <returns></returns>
        public bool OppositeVectors(Vector3 v1, Vector3 v2)
        {
            if (Math.Abs((v1.X * v2.Y) - (v2.X * v1.X)) < 0.5)
            {
                if (v1.X * v2.X < 0)
                {
                    return true;
                }
            }

            return false;              
        }
    }
}
